package org.ysling.litemall.wx.socket;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.ysling.litemall.core.utils.JacksonUtil;
import org.ysling.litemall.db.domain.LitemallMessage;
import org.ysling.litemall.db.domain.LitemallUser;
import org.ysling.litemall.db.service.LitemallMessageService;
import org.ysling.litemall.db.service.LitemallUserService;
import org.ysling.litemall.wx.util.UserTokenManager;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Comparator;
import java.util.List;

@Component
@ServerEndpoint(value = "/websocket/{token}/{receiveUserId}")
public class WebSocketService {

    private final Log logger = LogFactory.getLog(WebSocketService.class);

    private static LitemallUserService userService;

    private static LitemallMessageService messageService;

    @Autowired
    public void setUserService(LitemallUserService userService) {
        WebSocketService.userService = userService;
    }

    @Autowired
    public void setMessageService(LitemallMessageService messageService) {
        WebSocketService.messageService = messageService;
    }

    /**与某个客户端的连接对话，需要通过它来给客户端发送消息*/
    public Session session;
    /**标识当前连接客户端的用户名*/
    public Integer userId;

    /**
     * 打开连接触发事件
     * @param token 用户授权
     * @param receiveUserId 消息接收用户
     * @param session 用户会话
     */
    @OnOpen
    public void onOpen(@PathParam("token") String token , @PathParam("receiveUserId") Integer receiveUserId, Session session) {
        if (token == null || receiveUserId == null){
            WebSocketUtil.sendHintTo(session ,"用户信息获取失败");
            return;
        }
        //根据用户token获取用户id
        Integer userId = UserTokenManager.getUserId(token);
        if (userId == null) {
            WebSocketUtil.sendHintTo(session ,"登陆已失效，请重新登陆");
            return;
        }

        this.userId = userId;
        this.session = session;
        WebSocketUtil.socketMap.put(userId, this);

        //发给自己的消息
        List<LitemallMessage> meMessages = messageService.getHistoryMessage(userId, receiveUserId);
        //自己发的消息
        List<LitemallMessage> toMessages = messageService.getHistoryMessage(receiveUserId, userId);
        //合并历史消息
        meMessages.addAll(toMessages);
        //历史消息排序
        meMessages.sort(Comparator.comparing(LitemallMessage::getAddTime));
        //发送历史消息
        session.getAsyncRemote().sendText(JSONObject.toJSONString(meMessages));
        //打印日志
        logger.info(String.format("[WebSocket] 连接成功，当前连接人数为: = {%s}" , WebSocketUtil.socketMap.size()));
    }

    /**
     * 收到消息触发事件
     * @param body 信息
     */
    @OnMessage
    public void onMessage(@RequestBody String body) {
        //获取发送信息参数
        String[] messageImages = JacksonUtil.parseObject(body, "messageImage", String[].class);
        String avatarUrl = JacksonUtil.parseString(body, "avatarUrl");
        String content = JacksonUtil.parseString(body, "content");
        String nickName = JacksonUtil.parseString(body, "nickName");
        Integer receiveUserId = JacksonUtil.parseInteger(body, "receiveUserId");

        //心跳校验
        String token = JacksonUtil.parseString(body, "token");
        if (token != null){
            return;
        }

        //禁止发送空消息
        if (!StringUtils.hasText(content)) {
            if (messageImages == null || messageImages.length <= 0) {
                WebSocketUtil.sendHintTo(session, "发送信息不能为空");
                return;
            }
        }

        //如果消息发送数据为null则不发送
        if (!ObjectUtils.allNotNull(receiveUserId , avatarUrl , nickName , userId)){
            WebSocketUtil.sendHintTo(session ,"用户信息获取失败");
            return;
        }

        //禁止给自己发送信息
        if (userId.equals(receiveUserId)){
            WebSocketUtil.sendHintTo(session ,"禁止给自己发送信息");
            return;
        }

        //保存历史记录
        LitemallMessage message = new LitemallMessage();
        message.setNickname(nickName);
        message.setAvatar(avatarUrl);
        message.setContent(content);
        message.setSendUserId(userId);
        message.setPicUrls(messageImages);
        message.setReceiveUserId(receiveUserId);
        messageService.add(message);
        //发送消息
        WebSocketUtil.sendMessageTo(message , userId , receiveUserId);
        //不在线则发送订阅通知
        WebSocketService socketService = WebSocketUtil.socketMap.get(receiveUserId);
        if (socketService == null){
            LitemallUser user = userService.findById(receiveUserId);
        }

        //打印日志
        logger.info(String.format("[WebSocket] {%s}发送消息 = {%s}" , userId , body));
    }


    /**
     * 关闭连接触发事件
     */
    @OnClose
    public void onClose() {
        if (userId == null) return;
        WebSocketUtil.socketMap.remove(userId);
        logger.info(String.format("[WebSocket] 退出成功，当前连接人数为：={%s}",WebSocketUtil.socketMap.size()));
    }

    /**
     * 传输消息错误触发事件
     * @param error 异常信息
     */
    @OnError
    public void onError(Throwable error) {
        logger.info(String.format("[WebSocket] 信息发送错误{%s}",error.getMessage()));
    }

}
